package com.example.springboot.exception;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import  com.example.springboot.base.Result;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 全局异常处理 {@link #onException(Exception) } / 数据绑定 {@link #initBinder(WebDataBinder) }/ 响应增强 {@link #addAttribute(Model)}
 * <p> RestControllerAdvice 默认会扫描 所有的 @RestController
 * <p> 使用basePackages时，只会对 这些包下的Controller 生效
 * <p> annotations = RestController.class，只针对带特定注解的 Controller
 * <p> assignableTypes = {UserController.class, OrderController.class}，按类名过滤
 * <p> 可以配合使用，但是取 交集 使用
 * <p>
 * @author Zhang.Z
 * @version 2025-09-20
 */
@RestControllerAdvice( basePackages = {
    "com.example.springboot.controller"
})
public class GlobalExceptionHandler {


    /**
     * 全局异常处理，针对 Exception 异常
     */
    @ExceptionHandler(value = {Exception.class})
    public Result<String> onException(Exception ex){
        return Result.error(ex.getMessage());
    }

    /**
     * 全局异常处理，针对 RuntimeException 异常
     */
    @ExceptionHandler(value = RuntimeException.class)
    public Result<String> onException(RuntimeException ex){
        return Result.error(ex.getMessage());
    }

    /**
     * 响应增强
     * <p>搭配 @ModelAttribute，可以给所有请求方法统一传入一些模型数据
     */
    @ModelAttribute
    public void addAttribute(Model model) {
        model.addAttribute("author", "zz");
    }

    /**
     * <p>
     *     数据绑定
     * </p>
     * 1. 设置指定参数的转换方式，
     * <p> 例如：str -> data, str -> list等
     * <p> registerCustomEditor(Date.class, new CustomDateEditor) 表示对所有 Date 类型参数生效。
     * <p> allowEmpty参数表示允许空值 .
     * <p>
     *
     * 2. 防止参数注入漏洞（字段白名单 / 黑名单）
     * <p> setAllowedFields 只允许绑定 参数1、参数2...
     * <p> setDisallowedFields 禁止绑定 参数1、参数2...
     * <p>
     * 3. 全局数据校验
     * <p>  binder.setValidator(new MyCustomValidator()) 为绑定器设置校验器（Validator），让请求参数对象自动校验
     * <p>
     * 4. 字符串预处理（trim、XSS 过滤等）
     *
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 指定日期字符串的解析格式：yyyy-MM-dd
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false); // 严格解析
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }


}
